#include <bits/stdc++.h>
#include <pthread.h>
#include <unistd.h>
#include <semaphore.h>
#include "LockGuard.hpp"
template <class T>
class RingQueue{
    std::vector<T> _ringqueue;
    int _size;
    int _p_step;//生产者脚步
    int _c_step;//消费者脚步
    sem_t _space_sem; //生产者使用的信号量
    sem_t _data_sem;  //消费者使用的信号量
    int _occupy;
    pthread_mutex_t _c_mutex;
    pthread_mutex_t _p_mutex;
    void P(sem_t &sem)
    {
        sem_wait(&sem);
    }
    void V(sem_t &sem)
    {
        sem_post(&sem);
    }

public:
    RingQueue(int size = 5);
    ~RingQueue();
    void Push(const T& data);
    void Push(T&& data);
    void Pop(T* out);
};

template <class T>
RingQueue<T>::RingQueue(int size)
:_size(size)
,_ringqueue(size)
,_p_step(0)
,_c_step(0)
{
    sem_init(&_space_sem, 0, size);
    sem_init(&_data_sem, 0, 0);

    pthread_mutex_init(&_c_mutex,nullptr);
    pthread_mutex_init(&_p_mutex,nullptr);
}

template <class T>
RingQueue<T>::~RingQueue()
{
    sem_destroy(&_space_sem);
    sem_destroy(&_data_sem);

    pthread_mutex_destroy(&_c_mutex);
    pthread_mutex_destroy(&_p_mutex);
}

template <class T>
void RingQueue<T>::Push(const T& data)
{
    P(_space_sem);
    {
        LockGuard local_lock(_p_mutex);
        _ringqueue[_p_step++] = data;
        _p_step %= _size;
        _occupy++;
    }
    V(_data_sem);
}

template <class T>
void RingQueue<T>::Push( T&& data)
{
    P(_space_sem);
    {
        LockGuard local_lock(_p_mutex);
        _ringqueue[_p_step++] = data;
        _p_step %= _size;
        _occupy++;
    }
    V(_data_sem);
}


template <class T>
void RingQueue<T>::Pop(T* out)
{
    P(_data_sem);
    {
        LockGuard local_lock(_c_mutex);
        *out = _ringqueue[_c_step++]; 
        _c_step%=_size;
        _occupy--;
    }

    V(_space_sem);
}
